chore(admin): typesafe API client + TanStack Query rails (#7638)#7695
Conversation
…#2) * docs(admin): design for typesafe API client + TanStack Query rails (ether#7638) Rails-only scope: codegen toolchain, runtime client, and provider — no call-site migrations. Admin endpoints are not yet covered by the OpenAPI spec, so a separate issue will follow before any migration is useful. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): implementation plan for typesafe API client rails (ether#7638) Step-by-step task breakdown for the rails-only PR: codegen toolchain, runtime client, TanStack Query provider, CI freshness check, docs. No call-site migrations until admin endpoints are added to the OpenAPI spec (separate follow-up). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(api): export generateDefinitionForVersion from openapi hook Required by the admin codegen script (ether#7638) to dump the OpenAPI spec without booting Express. No behavior change for the request hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(admin): add OpenAPI codegen + TanStack Query deps (ether#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(admin): add OpenAPI spec dump entry (ether#7638) Loaded via tsx by gen-api.mjs in the next commit. Writes JSON to a file path argument so log4js stdout output (from Settings init) does not pollute the spec output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(admin): wire OpenAPI codegen into build (ether#7638) Adds gen:api script and amends build/build-copy to regenerate admin/src/api/schema.d.ts before compiling. The generated file is checked in so it shows up in PR review and so a fresh checkout doesn't need codegen to typecheck. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): typed openapi-fetch + react-query client (ether#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): TanStack Query provider, dev-only devtools (ether#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): mount TanStack Query provider at root (ether#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(admin): smoke test for typed openapi-fetch client (ether#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(admin): verify generated OpenAPI schema is up to date (ether#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): document OpenAPI codegen workflow (ether#7638) Replaces the default Vite scaffold README with admin-specific scripts table and codegen workflow notes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * build(admin): exclude __tests__ from tsc include (ether#7638) The smoke test imports node:test/node:assert which need @types/node. Admin source is browser-only, so excluding __tests__ from the production typecheck is cleaner than adding Node types to the bundle config. The test still runs under tsx, which doesn't share this constraint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: regenerate lockfile with pnpm 10 to restore overrides block (ether#7638) Adding admin deps with pnpm 11 stripped the top-level \`overrides:\` section from pnpm-lock.yaml, which CI uses pnpm 10 to verify. Result: ERR_PNPM_LOCKFILE_CONFIG_MISMATCH on every job. Re-running pnpm 10 \`install --lockfile-only\` restores the overrides block; the new admin package entries land in the same commit. Two stale lockfile entries not present in package.json (\`serialize-javascript\` version pin and \`uuid@<14.0.0\`) were normalized by the regen — package.json is the source of truth for those. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * build(docker): preserve strictDepBuilds=false in trimmed workspace yaml (ether#7638) Adding tsx as an admin devDep brings esbuild@0.27.x into the resolved subgraph, and the Dockerfile's runtime stage was overwriting pnpm-workspace.yaml with a stripped-down version that lost the strictDepBuilds=false setting from the source repo. With pnpm 10's default of strictDepBuilds=true, the install then errors on ERR_PNPM_IGNORED_BUILDS for esbuild + scarf rather than warning. Restore the strictDepBuilds=false and the @scarf/scarf ignore in the trimmed yaml so the production install matches develop's behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(admin): point client baseUrl at /api/<version> via codegen (ether#7638) Qodo flagged: with baseUrl='/' and schema paths like '/createGroup', calls landed at /createGroup, but the backend mounts the FLAT-style spec under /api/<version>/. So once a call site lands, every request 404s. gen:api now also emits admin/src/api/version.ts containing LATEST_API_VERSION (read from info.version in the spec) and a derived API_BASE_URL = `/api/<version>`. client.ts imports API_BASE_URL. Workflow freshness check covers both generated files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * build(admin): cross-platform spawn in gen-api.mjs (ether#7638) Windows CI failed because spawnSync('pnpm', ...) cannot resolve pnpm.cmd without a shell. Set shell:true on win32 only so Linux/macOS runs avoid Node's DEP0190 warning. All spawn args are literal strings, so the shell variant is not an injection risk. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one. |
|
/review |
ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one. |
Code Review by Qodo
1. Schema lacks /admin-auth paths
|
Review Summary by QodoSet up typesafe OpenAPI admin API client with TanStack Query and codegen rails
WalkthroughsDescription• Establishes foundational infrastructure for a typesafe, OpenAPI-derived admin API client backed by TanStack Query • Implements codegen toolchain (pnpm --filter admin gen:api) that produces admin/src/api/schema.d.ts and admin/src/api/version.ts from the OpenAPI spec builder • Creates runtime client (openapi-fetch + openapi-react-query) at admin/src/api/client.ts with automatic baseUrl configuration pointing to /api/<version>/ • Mounts <QueryProvider> at admin root with dev-only React Query devtools (excluded from production bundle) • Adds CI freshness check in frontend-admin-tests.yml to ensure generated files stay synchronized with the source spec • Includes comprehensive documentation (design spec, implementation plan, and updated admin README) explaining the workflow • Adds smoke test verifying the API client module loads correctly • Exports OpenAPI spec builder functions from core etherpad modules to enable external codegen pipeline • No call sites migrated yet; admin endpoints must be added to OpenAPI spec before migrations are useful Diagramflowchart LR
A["OpenAPI Spec<br/>in Express"] -->|"dump-spec.ts"| B["OpenAPI JSON"]
B -->|"openapi-typescript"| C["schema.d.ts<br/>version.ts"]
C -->|"import"| D["client.ts<br/>fetchClient + $api"]
D -->|"use"| E["React Components"]
F["QueryProvider.tsx"] -->|"wrap"| E
G["CI Check"] -->|"verify"| C
File Changes1. admin/src/api/schema.d.ts
|
Code Review by Qodo
Context used 1. schema.d.ts missing /admin-auth paths
|
| The admin endpoints are not yet present in the OpenAPI spec — this client is | ||
| in place to support upcoming work (see issue #7638 follow-up). For now, it is | ||
| exercised only by the smoke test. |
There was a problem hiding this comment.
1. schema.d.ts missing /admin-auth paths 📎 Requirement gap ≡ Correctness
The generated admin OpenAPI schema/types do not include any /admin-auth/* operations, so the typed client cannot cover the admin authentication endpoints the UI uses. This fails the requirement that /admin-auth/* be represented in the OpenAPI output used for codegen.
Agent Prompt
## Issue description
The OpenAPI-generated admin types do not include `/admin-auth/*` operations, so the typed client cannot be used for existing admin auth calls.
## Issue Context
The admin schema is generated from the OpenAPI hook output, and the compliance requirement for this PR expects `/admin-auth/*` endpoints to be included in that output so `admin/src/api/schema.d.ts` exposes typed paths/operations.
## Fix Focus Areas
- src/node/hooks/express/openapi.ts[422-575]
- admin/src/api/schema.d.ts[9-31]
- admin/README.md[65-67]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| // GENERATED — do not edit. Run `pnpm --filter admin gen:api` to regenerate. | ||
| // Source: src/node/hooks/express/openapi.ts (#7638) | ||
|
|
||
| /** | ||
| * This file was auto-generated by openapi-typescript. | ||
| * Do not make direct changes to the file. | ||
| */ |
There was a problem hiding this comment.
2. Generated schema committed 📘 Rule violation ⚙ Maintainability
This PR adds generated files (admin/src/api/schema.d.ts, admin/src/api/version.ts) and documents/enforces committing them via CI. This violates the policy against committing generated build/runtime artifacts.
Agent Prompt
## Issue description
Generated files (`admin/src/api/schema.d.ts`, `admin/src/api/version.ts`) are committed and CI enforces that workflow, which violates the repository compliance rule against committing generated artifacts.
## Issue Context
The generator is already wired into the admin build (`pnpm gen:api`), so the repo can instead generate these files during build/CI without storing outputs in git.
## Fix Focus Areas
- admin/src/api/schema.d.ts[1-7]
- admin/src/api/version.ts[1-5]
- admin/package.json[7-20]
- .github/workflows/frontend-admin-tests.yml[71-80]
- admin/README.md[34-40]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| export interface paths { | ||
| "/createGroup": { | ||
| parameters: { | ||
| query?: never; | ||
| header?: never; | ||
| path?: never; | ||
| cookie?: never; | ||
| }; | ||
| /** creates a new group */ | ||
| get: operations["createGroupUsingGET"]; | ||
| put?: never; | ||
| /** creates a new group */ | ||
| post: operations["createGroupUsingPOST"]; | ||
| delete?: never; | ||
| options?: never; | ||
| head?: never; | ||
| patch?: never; | ||
| trace?: never; | ||
| }; | ||
| "/createGroupIfNotExistsFor": { | ||
| parameters: { | ||
| query?: never; | ||
| header?: never; |
There was a problem hiding this comment.
1. Schema lacks /admin-auth paths 📎 Requirement gap ≡ Correctness
The generated admin/src/api/schema.d.ts does not include any /admin-auth/* (or /admin/*) paths, and the updated README explicitly notes admin endpoints are not yet in the OpenAPI spec. This fails the requirement that the OpenAPI-derived admin schema reflects the admin UI authentication/admin endpoint surface.
Agent Prompt
## Issue description
The generated admin OpenAPI TypeScript schema does not expose any `/admin-auth/*` or `/admin/*` typed paths, so the new typed client cannot be used for real admin UI traffic.
## Issue Context
The compliance checklist requires the OpenAPI spec (and therefore the generated `admin/src/api/schema.d.ts`) to include the admin authentication and admin endpoint surfaces.
## Fix Focus Areas
- src/node/hooks/express/openapi.ts[769-774]
- admin/src/api/schema.d.ts[9-31]
- admin/README.md[65-67]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const tmpDir = mkdtempSync(path.join(tmpdir(), 'etherpad-openapi-')); | ||
| const specPath = path.join(tmpDir, 'spec.json'); | ||
|
|
||
| // On Windows pnpm resolves to pnpm.cmd, which spawnSync can only find via a | ||
| // shell. Use shell on Windows only to avoid Node's DEP0190 warning elsewhere. | ||
| // Every argument here is fixed (no user input) so the shell:true variant is | ||
| // not an injection risk. | ||
| const spawnOpts = { | ||
| cwd: adminRoot, | ||
| stdio: 'inherit', | ||
| shell: process.platform === 'win32', | ||
| }; | ||
|
|
||
| try { | ||
| const dump = spawnSync( | ||
| 'pnpm', | ||
| ['exec', 'tsx', 'scripts/dump-spec.ts', specPath], | ||
| spawnOpts, | ||
| ); | ||
| if (dump.status !== 0) { | ||
| console.error(`dump-spec.ts failed with exit code ${dump.status}`); | ||
| process.exit(dump.status ?? 1); | ||
| } | ||
|
|
||
| const gen = spawnSync( | ||
| 'pnpm', | ||
| ['exec', 'openapi-typescript', specPath, '-o', outFile], | ||
| spawnOpts, | ||
| ); |
There was a problem hiding this comment.
3. Windows gen:api arg splitting 🐞 Bug ☼ Reliability
admin/scripts/gen-api.mjs uses shell: true on Windows while passing file paths (tmpdir + repo paths) as arguments; if those paths contain spaces (common in Windows user temp dirs), cmd.exe tokenization can break the pnpm exec ... <path> calls and make pnpm gen:api fail.
Agent Prompt
### Issue description
`admin/scripts/gen-api.mjs` sets `shell: process.platform === 'win32'` and then calls `spawnSync('pnpm', [..., specPath], spawnOpts)`. On Windows, enabling the shell can cause argument parsing issues for paths that include spaces (common for user temp directories), breaking `pnpm gen:api`.
### Issue Context
The script enables `shell` only to make `pnpm` resolvable on Windows. This can be solved without `shell: true` by invoking the correct executable name on Windows.
### Fix Focus Areas
- admin/scripts/gen-api.mjs[19-54]
### Suggested change
- Use `const pnpmCmd = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';`
- Keep `shell: false` (or omit it) in `spawnOpts`.
- Replace both `spawnSync('pnpm', ...)` calls with `spawnSync(pnpmCmd, ...)`.
This avoids cmd.exe parsing entirely while still working on Windows.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
…pt (ether#7638) Qodo flagged the committed admin/src/api/schema.d.ts as a build artifact that violates the rule against committing generated files (rule 467291, "Exclude build artifacts and runtime-generated files from version control"). This commit: - Adds admin/src/api/{schema.d.ts,version.ts} to .gitignore. - Removes both from VCS (the prior squash had committed them). - Chains \`gen:api\` into the dev and test scripts so a fresh checkout lands a working dev server / test run without an extra step. build and build-copy already chained gen:api. - Drops the now-redundant CI freshness diff step from frontend-admin-tests.yml — with the files no longer committed, the build step's gen:api invocation is the only check needed. - Updates admin/README.md to describe the new generated-file workflow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Qodo's earlier rule violation on the JohnMcLear/etherpad fork PR (rule 467291: "Exclude build artifacts and runtime-generated files from version control") is now addressed in 40fe8a4:
|
…ther#7693) Address Qodo finding 2 (correctness bug). The merged schema introduced in this PR exposes both public-API paths (under /api/<version>/) and admin paths (at root, e.g. /admin-auth/). The single fetchClient from ether#7695 has baseUrl=API_BASE_URL ("/api/<version>"), so calling an admin path through it would resolve to /api/<version>/admin-auth/ — wrong. Fix: - Narrow the generated `paths` interface by URL prefix (`/admin*` vs everything else). - Export two clients: `fetchClient` (public, baseUrl=/api/<version>) and `adminFetchClient` (admin, baseUrl='/'). - Mirror with `$api` / `$adminApi` query hook factories. TypeScript now rejects mixing surfaces at compile time: fetchClient.GET('/admin-auth/') // type error: not in PublicPaths adminFetchClient.GET('/createGroup') // type error: not in AdminPaths Smoke test updated to assert all four exports exist. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(admin): typesafe API client + TanStack Query rails (#7638) (#2) * docs(admin): design for typesafe API client + TanStack Query rails (#7638) Rails-only scope: codegen toolchain, runtime client, and provider — no call-site migrations. Admin endpoints are not yet covered by the OpenAPI spec, so a separate issue will follow before any migration is useful. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): implementation plan for typesafe API client rails (#7638) Step-by-step task breakdown for the rails-only PR: codegen toolchain, runtime client, TanStack Query provider, CI freshness check, docs. No call-site migrations until admin endpoints are added to the OpenAPI spec (separate follow-up). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(api): export generateDefinitionForVersion from openapi hook Required by the admin codegen script (#7638) to dump the OpenAPI spec without booting Express. No behavior change for the request hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(admin): add OpenAPI codegen + TanStack Query deps (#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(admin): add OpenAPI spec dump entry (#7638) Loaded via tsx by gen-api.mjs in the next commit. Writes JSON to a file path argument so log4js stdout output (from Settings init) does not pollute the spec output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(admin): wire OpenAPI codegen into build (#7638) Adds gen:api script and amends build/build-copy to regenerate admin/src/api/schema.d.ts before compiling. The generated file is checked in so it shows up in PR review and so a fresh checkout doesn't need codegen to typecheck. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): typed openapi-fetch + react-query client (#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): TanStack Query provider, dev-only devtools (#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): mount TanStack Query provider at root (#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(admin): smoke test for typed openapi-fetch client (#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(admin): verify generated OpenAPI schema is up to date (#7638) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): document OpenAPI codegen workflow (#7638) Replaces the default Vite scaffold README with admin-specific scripts table and codegen workflow notes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * build(admin): exclude __tests__ from tsc include (#7638) The smoke test imports node:test/node:assert which need @types/node. Admin source is browser-only, so excluding __tests__ from the production typecheck is cleaner than adding Node types to the bundle config. The test still runs under tsx, which doesn't share this constraint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: regenerate lockfile with pnpm 10 to restore overrides block (#7638) Adding admin deps with pnpm 11 stripped the top-level \`overrides:\` section from pnpm-lock.yaml, which CI uses pnpm 10 to verify. Result: ERR_PNPM_LOCKFILE_CONFIG_MISMATCH on every job. Re-running pnpm 10 \`install --lockfile-only\` restores the overrides block; the new admin package entries land in the same commit. Two stale lockfile entries not present in package.json (\`serialize-javascript\` version pin and \`uuid@<14.0.0\`) were normalized by the regen — package.json is the source of truth for those. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * build(docker): preserve strictDepBuilds=false in trimmed workspace yaml (#7638) Adding tsx as an admin devDep brings esbuild@0.27.x into the resolved subgraph, and the Dockerfile's runtime stage was overwriting pnpm-workspace.yaml with a stripped-down version that lost the strictDepBuilds=false setting from the source repo. With pnpm 10's default of strictDepBuilds=true, the install then errors on ERR_PNPM_IGNORED_BUILDS for esbuild + scarf rather than warning. Restore the strictDepBuilds=false and the @scarf/scarf ignore in the trimmed yaml so the production install matches develop's behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(admin): point client baseUrl at /api/<version> via codegen (#7638) Qodo flagged: with baseUrl='/' and schema paths like '/createGroup', calls landed at /createGroup, but the backend mounts the FLAT-style spec under /api/<version>/. So once a call site lands, every request 404s. gen:api now also emits admin/src/api/version.ts containing LATEST_API_VERSION (read from info.version in the spec) and a derived API_BASE_URL = `/api/<version>`. client.ts imports API_BASE_URL. Workflow freshness check covers both generated files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * build(admin): cross-platform spawn in gen-api.mjs (#7638) Windows CI failed because spawnSync('pnpm', ...) cannot resolve pnpm.cmd without a shell. Set shell:true on win32 only so Linux/macOS runs avoid Node's DEP0190 warning. All spawn args are literal strings, so the shell variant is not an injection risk. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(admin): gitignore generated schema/version, regen on every script (#7638) Qodo flagged the committed admin/src/api/schema.d.ts as a build artifact that violates the rule against committing generated files (rule 467291, "Exclude build artifacts and runtime-generated files from version control"). This commit: - Adds admin/src/api/{schema.d.ts,version.ts} to .gitignore. - Removes both from VCS (the prior squash had committed them). - Chains \`gen:api\` into the dev and test scripts so a fresh checkout lands a working dev server / test run without an extra step. build and build-copy already chained gen:api. - Drops the now-redundant CI freshness diff step from frontend-admin-tests.yml — with the files no longer committed, the build step's gen:api invocation is the only check needed. - Updates admin/README.md to describe the new generated-file workflow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): design for admin OpenAPI coverage (#7693) Adds the design doc for documenting `/admin-auth/*` and `/admin/update/status` in the OpenAPI spec so the typed client generated by #7695 (`admin/src/api/ schema.d.ts`) gains admin call-sites the day it lands. This PR is stacked on #7695 — codegen rails must merge first. Schema-only, no call-site migrations (those are an explicit follow-up named in #7693). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): correct UpdateStatus schema to base-branch shape (#7693) The first draft mirrored the Tier 2 (#7607) response shape, but this PR stacks on #7695 whose updateStatus.ts only emits the Tier 1 fields. Fix the schema, install-method enum, and tier enum to match types.ts and the actual handler. Tier 2 amends UpdateStatus when it lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): implementation plan for admin OpenAPI coverage (#7693) Step-by-step task breakdown for the schema-only PR: stub the document, add /admin-auth/ + /admin/update/status paths and sub-schemas, collision regression, /admin/openapi.json route, codegen merge, and CI verification. No call-site migrations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): stub OpenAPI document for admin endpoints (#7693) Adds generateAdminDefinition() returning a minimal valid OpenAPI 3.0 document with no paths yet, plus security schemes for the two auth modes (Basic + session cookie). Subsequent tasks fill in the actual admin paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): document POST /admin-auth/ in OpenAPI (#7693) Adds verifyAdminAccess as the operation that the admin UI's LoginScreen and App session check both call. Documents Basic auth, session cookie, and anonymous request modes plus their 200/401/403 responses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): document GET /admin/update/status in OpenAPI (#7693) Adds getUpdateStatus operation plus UpdateStatus, ReleaseInfo, PolicyResult, and VulnerableBelowDirective sub-schemas. Property names and enums mirror src/node/updater/types.ts and the response object emitted by updateStatus.ts. Tier 2 (#7607) will amend UpdateStatus when it ships execution/lastResult/lockHeld. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(admin): regression net for admin/public OpenAPI collisions (#7693) Cross-checks admin paths, operationIds, and schema names against the latest public spec. Today there are no overlaps; the test exists to catch future renames before they break the merged client codegen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): expose admin OpenAPI doc at /admin/openapi.json (#7693) Mounts the admin OpenAPI document at /admin/openapi.json (CORS: *) via an expressPreSession hook, matching the /api/openapi.json convention. The admin SPA wildcard at /admin/{*filename} registers later in expressCreateServer, so the JSON route wins. Live-route test confirms JSON content-type and CORS header. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): mergeOpenAPI helper for codegen pipeline (#7693) Pure-JS deep-merge of two OpenAPI 3.0 documents. Unions paths and components by key; throws on collisions. Public document's info, servers, and root security win over the admin document's. Used by dump-spec.ts to produce a single merged JSON for openapi-typescript. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): fix stale "Section 3" reference in spec (#7693) Drafting numbered the design walkthrough; final spec uses titled sections. Update the back-reference accordingly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(admin): include admin OpenAPI in generated client (#7693) Modifies dump-spec.ts to import generateAdminDefinition alongside the public generator and feed both through mergeOpenAPI before writing the JSON consumed by openapi-typescript. The resulting admin/src/api/ schema.d.ts paths interface now exposes /admin-auth/ and /admin/update/status, ready for typed call-site adoption in a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(admin): gate /admin/openapi.json behind a feature flag (#7693) Address Qodo finding 1: new features must ship behind a flag, disabled by default (CONTRIBUTING.md, AGENTS.MD, best_practices.md). Adds settings.adminOpenAPI.enabled (default false). expressPreSession returns early when the flag is off, so the route is dormant on a fresh install. The codegen pipeline imports generateAdminDefinition() in-process and does not depend on the runtime route, so default-off has no effect on the typed client. Operators who want third-party tooling (Postman, swagger-ui, downstream clients) to consume the spec at runtime opt in via settings. Adds: - SettingsType + defaults entry in src/node/utils/Settings.ts - settings.json.template documentation - A backend spec asserting expressPreSession is a no-op when the flag is off (live route test now sets the flag explicitly) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(admin): split fetchClient by surface; admin client baseUrl='/' (#7693) Address Qodo finding 2 (correctness bug). The merged schema introduced in this PR exposes both public-API paths (under /api/<version>/) and admin paths (at root, e.g. /admin-auth/). The single fetchClient from #7695 has baseUrl=API_BASE_URL ("/api/<version>"), so calling an admin path through it would resolve to /api/<version>/admin-auth/ — wrong. Fix: - Narrow the generated `paths` interface by URL prefix (`/admin*` vs everything else). - Export two clients: `fetchClient` (public, baseUrl=/api/<version>) and `adminFetchClient` (admin, baseUrl='/'). - Mirror with `$api` / `$adminApi` query hook factories. TypeScript now rejects mixing surfaces at compile time: fetchClient.GET('/admin-auth/') // type error: not in PublicPaths adminFetchClient.GET('/createGroup') // type error: not in AdminPaths Smoke test updated to assert all four exports exist. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(admin): spec — feature flag + dual-client design (#7693) Reflect Qodo-driven changes: - /admin/openapi.json route is now feature-flagged (default off). - admin/src/api/client.ts splits paths by URL prefix and exports two clients (public + admin) so TypeScript rejects mixing surfaces. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(admin): check adminOpenAPI flag per-request, not at hook setup (#7693) The first feature-flag commit (dbcfb39) gated the route by checking the flag inside expressPreSession and skipping app.get() when off. That broke under the full backend suite because common.init() is cached: the first spec that calls it boots the server with whatever flag state was present at that moment, and later specs cannot retroactively register the route by toggling the flag. Move the flag check inside the request handler: - Route is always registered. - Handler returns 404 application/json when the flag is off (so callers get a clear "feature disabled" signal rather than the SPA wildcard's text/html catch-all). - Handler returns the spec + CORS * when the flag is on. Tests now toggle the flag in-process and exercise both states against the shared agent — no server restart needed. Added a "returns 404 JSON when off" test alongside the existing "200 + spec + CORS when on". Full backend suite: 1007 passing, 6 pending, 0 failures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts: # admin/package.json # admin/scripts/dump-spec.ts # admin/src/api/__tests__/client.test.ts # admin/src/api/client.ts # pnpm-lock.yaml
Summary
Lays down the rails for a typesafe, OpenAPI-derived admin API client backed by TanStack Query. Closes #7638.
pnpm --filter admin gen:api) producingadmin/src/api/schema.d.tsandadmin/src/api/version.tsfromsrc/node/hooks/express/openapi.ts.openapi-fetch+openapi-react-query) atadmin/src/api/client.tswithbaseUrl = \/api/${LATEST_API_VERSION}`so calls land at/api//createGroup`.<QueryProvider>mounted at the admin root with dev-only React Query devtools (verified absent from the production bundle).frontend-admin-tests.yml.admin/README.mddocumenting the workflow.No call sites migrated. Admin endpoints aren't in the OpenAPI spec yet — that gap is filed as #7693 and must land before any migration is useful.
Why one squashed commit
This was developed iteratively on the fork (JohnMcLear#2 — merged into the fork's
develop) with 16 small fixup commits along the way (Windows shell, Dockerfile workspace yaml, lockfile overrides, baseUrl emit, etc.). Squashed for upstream so review is one cohesive change rather than the back-and-forth.Semver
Patch — build tooling + currently-unused runtime libs, no observable behavior change.
Test plan
pnpm --filter admin gen:apiruns clean (48 paths, OpenAPI 3.0.2, version 1.3.1)pnpm --filter admin run buildsucceeds; production bundle excludesReactQueryDevtoolspnpm --filter admin testpasses (smoke test: 1 pass)pnpm ts-checkclean for admin/openapi files@tanstack/react-query-devtools(verifiedimport.meta.env.DEV === trueand the lazy import is rendered)🤖 Generated with Claude Code